"""
В этом фале будут располагаться хендлеры, отвечающие за отображение личного кабинета и его
составляющих
"""
import datetime
import random

from aiocryptopay import AioCryptoPay
from aiogram import types
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from pyqiwip2p import QiwiP2P

import client_kb
import sqlite_db
from config import Settings
from main import dp


class FSM(StatesGroup):
    balance_choice_pay = State()
    balance_summa_qiwi = State()
    balance_summa_crypto = State()

    subscription_choise_type = State()
    subscription_choise_pay = State()


@dp.message_handler(Text(equals="Личный кабинет 💼"), state="*")
async def command_personal_cabinet(message: types.Message):
    """
    Вывод личного кабинета пользователя
    """
    user_id = message.from_user.id
    await sqlite_db.check_user_in_db(user_id)
    balance, middle_time = await sqlite_db.get_user_details_from_db(user_id)

    if middle_time <= 0:
        subscription_status = "Нет ❌"
    else:
        subscription_status = str(datetime.timedelta(seconds=middle_time))

    await message.answer(
        f"🏠 Личный кабинет 🛠\n"
        f"Здесь ты можешь узнать свой баланс и пополнить его\n\n"
        f"Ваш 🆔: {user_id}\n"
        f"Баланс 💰: {balance} руб.\n"
        f"Подписка: {subscription_status}",
        reply_markup=client_kb.kb_top_up_balance,
    )


@dp.callback_query_handler(Text(equals="top_up_balance"), state="*")
async def command_top_up_balance(call: types.CallbackQuery):
    """
    Обрабатывает нажатие кнопки "Пополнить баланс" и предлагает пользователю выбрать способ оплаты.
    """
    await call.message.answer(
        f"Выберите способ оплаты по кнопке ниже", reply_markup=client_kb.kb_choise_pay
    )
    await call.answer()
    await FSM.balance_choice_pay.set()


@dp.callback_query_handler(Text(equals="choice_qiwi"), state=FSM.balance_choice_pay)
async def balance_summa_qiwi(call: types.CallbackQuery):
    """
    Обрабатывает выбор способа оплаты через Qiwi и просит пользователя ввести сумму пополнения баланса.
    """
    await call.message.delete()
    await call.message.answer(
        f"Введите сумму в рублях, на которую вы хотите пополнить баланс",
        reply_markup=client_kb.kb_cancel,
    )
    await call.answer()
    await FSM.balance_summa_qiwi.set()


@dp.message_handler(state=FSM.balance_summa_qiwi)
async def top_up_balance_qiwi(message: types.Message, state: FSMContext, p2p: QiwiP2P):
    """
    Обрабатывает ввод суммы для пополнения баланса через Qiwi и генерирует счет для оплаты.
    """
    user_id = message.from_user.id
    price = message.text
    await state.finish()
    if price.isdigit():
        comment = str(user_id) + "_" + str(random.randint(1000, 9999))
        bill = p2p.bill(amount=price, lifetime=180, comment=comment)
        await sqlite_db.add_check_balance_qiwi(user_id, bill.bill_id, price)
        check_pay1 = await message.answer(
            f'Чтобы пополнить баланс личного кабинета нажмите на кнопку "Оплатить"\n\n'
            f"Сумма: {price} ₽\n",
            reply_markup=client_kb.buy_menu_balance_qiwi(
                url=bill.pay_url, bill=bill.bill_id
            ),
        )
        async with state.proxy() as data:
            data["check_pay1"] = check_pay1["message_id"]
    else:
        await message.answer("Нужно ввести цифру", reply_markup=client_kb.kb_cancel)


@dp.callback_query_handler(text_contains="bqcheck_")
async def check_balance_qiwi(
    call: types.CallbackQuery, state: FSMContext, p2p: QiwiP2P
):
    """
    Проверяет статус оплаты счета Qiwi и обновляет баланс пользователя в случае успешной оплаты.
    """
    user_id = call.from_user.id
    bill = str(call.data[8:])
    info = await sqlite_db.get_check_balance_qiwi(bill)
    print(str(p2p.check(bill_id=bill).status))
    if info:
        if str(p2p.check(bill_id=bill).status) == "PAID":
            async with state.proxy() as data:
                try:
                    await dp.bot.delete_message(
                        chat_id=call.from_user.id, message_id=data["check_pay1"]
                    )
                except:
                    pass
                try:
                    await dp.bot.delete_message(
                        chat_id=call.from_user.id, message_id=data["check_pay2"]
                    )
                except:
                    pass
            await sqlite_db.sql_give_balance_qiwi(user_id, bill)
        else:
            async with state.proxy() as data:
                try:
                    await dp.bot.delete_message(
                        chat_id=call.from_user.id, message_id=data["check_pay2"]
                    )
                except:
                    pass
            check_pay2 = await call.message.answer(
                f"<b>Вы пока не оплатили счет</b>",
                parse_mode="HTML",
                reply_markup=client_kb.buy_menu_balance_qiwi(False, bill=bill),
            )
            async with state.proxy() as data:
                data["check_pay2"] = check_pay2["message_id"]
    else:
        await call.message.answer("Счет не найден")


@dp.callback_query_handler(Text(equals="choice_crypto"), state=FSM.balance_choice_pay)
async def balance_summa_crypto(call: types.CallbackQuery):
    """
    Предлагает пользователю ввести сумму в USDT для пополнения баланса через криптовалюту.
    """
    await call.message.delete()
    await call.message.answer(
        f"Введите сумму в USDT, на которую вы хотите пополнить баланс",
        reply_markup=client_kb.kb_cancel,
    )
    await call.answer()
    await FSM.balance_summa_crypto.set()


@dp.message_handler(state=FSM.balance_summa_crypto)
async def top_up_balance_crypto(
    message: types.Message, state: FSMContext, crypto: AioCryptoPay
):
    """
    Обрабатывает ввод суммы для пополнения баланса через криптовалюту и генерирует счет для оплаты.
    """
    await state.finish()
    price = message.text
    if price.isdigit():
        bill = await crypto.create_invoice(asset="USDT", amount=float(price))
        bill_id = bill.invoice_id
        await sqlite_db.add_check_balance_crypto(message.from_user.id, bill_id, price)
        await message.answer(
            f'Чтобы пополнить баланс личного кабинета нажмите на кнопку "Оплатить"\n\n'
            f"Сумма: {price} USDT\n\n"
            f"После оплаты вернитесь в этот бот и завершите покупку",
            reply_markup=client_kb.buy_menu_balance_crypto(
                url=bill.pay_url, bill=bill_id
            ),
        )
    else:
        await message.answer("нужно ввести цифру", reply_markup=client_kb.kb_cancel)


@dp.callback_query_handler(text_contains="bccheck_")
async def check_balance_crypto(call: types.CallbackQuery, crypto: AioCryptoPay):
    """
    Проверяет статус оплаты криптовалютного счета и обновляет баланс пользователя в случае успешной оплаты.
    """
    bill_id = str(call.data[8:])
    info = await sqlite_db.get_check_balance_crypto(bill_id)
    if info:
        invoices = await crypto.get_invoices(invoice_ids=int(bill_id))
        if str(invoices.status) == "paid":
            await call.message.delete()
            await sqlite_db.sql_give_balance_crypto(call.from_user.id, bill_id, crypto)
        else:
            await call.message.answer(
                f"<b>Вы пока не оплатили счет</b>",
                reply_markup=client_kb.buy_menu_balance_crypto(False, bill=bill_id),
            )
    else:
        await call.message.answer("Счет не найден")


@dp.callback_query_handler(Text(equals="top_up_subscription"))
async def command_subscription_type(call: types.CallbackQuery, config: Settings):
    """
    Предлагает пользователю выбрать тип подписки для покупки.
    """
    await call.message.answer(
        f"Выберите нужную подписку:\n\n"
        f"Неделя - {config.payment.price_sub_week} руб.\n"
        f"Месяц - {config.payment.price_sub_month} руб.",
        reply_markup=client_kb.kb_choise_sub_type,
    )
    await call.answer()
    await FSM.subscription_choise_type.set()


@dp.callback_query_handler(
    Text(equals=["sub_type_week", "sub_type_mounth"]),
    state=FSM.subscription_choise_type,
)
async def command_top_up_subscription_choise(call: types.CallbackQuery):
    """
    Обрабатывает выбор типа подписки пользователя и предлагает способы оплаты.
    """
    sub_type = "week" if call.data == "sub_type_week" else "mounth"
    if await sqlite_db.sql_check_what_money_to_sub(call.from_user.id, sub_type):
        await call.message.answer(
            f"На вашем балансе хватает денег, чтобы оплатить выбранную подписку\n"
            f"Подтвердите оплату",
            reply_markup=client_kb.kb_payed_with_balance_sub,
        )
    else:
        await call.message.answer(
            f"Выберите способ оплаты по кнопке ниже",
            reply_markup=client_kb.kb_choise_pay,
        )
    await call.answer()
    await FSM.subscription_choise_pay.set()


@dp.callback_query_handler(
    text_contains="pay_with_balance_sub", state=FSM.subscription_choise_pay
)
async def pay_sub_on_balance(call: types.CallbackQuery, config: Settings):
    """
    Обрабатывает оплату подписки с баланса пользователя.
    """
    sub_type = "week" if call.data == "sub_type_week" else "mounth"
    price = (
        float(config.payment.price_sub_week)
        if sub_type == "week"
        else float(config.payment.price_sub_month)
    )
    await sqlite_db.sql_give_sub_on_balance(call.from_user.id, price, sub_type)


@dp.callback_query_handler(
    Text(equals="choice_qiwi"), state=FSM.subscription_choise_pay
)
async def top_up_subscription_qiwi(
    call: types.CallbackQuery, config: Settings, p2p: QiwiP2P
):
    user_id = call.from_user.id
    sub_type = "week" if call.data == "sub_type_week" else "mounth"
    price = (
        float(config.payment.price_sub_week)
        if sub_type == "week"
        else float(config.payment.price_sub_month)
    )
    comment = str(user_id) + "_" + str(random.randint(1000, 9999))
    bill = p2p.bill(amount=price, lifetime=180, comment=comment)
    await sqlite_db.add_check_subscription(user_id, bill.bill_id, sub_type)
    check_pay1 = await call.message.answer(
        f'Чтобы оплатить подписку нажмите на кнопку "Оплатить"\n\n'
        f"Сумма: {price} ₽\n",
        reply_markup=client_kb.buy_menu_subscription_qiwi(
            url=bill.pay_url, bill=bill.bill_id
        ),
    )


@dp.callback_query_handler(text_contains="sqcheck_", state=FSM.subscription_choise_pay)
async def check_subscription_qiwi(call: types.CallbackQuery, p2p: QiwiP2P):
    user_id = call.from_user.id
    bill = str(call.data[8:])
    info = await sqlite_db.get_check_subscription(bill)
    if info:
        if str(p2p.check(bill_id=bill).status) == "PAID":
            await sqlite_db.sql_give_subscription(user_id, bill)
        else:
            check_pay2 = await call.message.answer(
                "<b>Вы пока не оплатили счет</b>",
                parse_mode="HTML",
                reply_markup=client_kb.buy_menu_subscription_qiwi(False, bill=bill),
            )
    else:
        await call.message.answer("Счет не найден")


@dp.callback_query_handler(
    Text(equals="choice_crypto"), state=FSM.subscription_choise_pay
)
async def top_up_subscription_crypto(
    call: types.CallbackQuery, config: Settings, crypto: AioCryptoPay
):
    user_id = call.from_user.id
    sub_type = "week" if call.data == "sub_type_week" else "mounth"
    price = (
        float(config.payment.price_sub_week)
        if sub_type == "week"
        else float(config.payment.price_sub_month_crypto)
    )
    bill = await crypto.create_invoice(asset="USDT", amount=float(price))
    bill_id = bill.invoice_id
    await sqlite_db.add_check_subscription(user_id, bill_id, sub_type)
    await call.message.answer(
        f'Чтобы оплатить подписку нажмите на кнопку "Оплатить"\n\n'
        f"Сумма: {price} USDT\n\n"
        f"После оплаты вернитесь в этот бот и завершите покупку",
        reply_markup=client_kb.buy_menu_subscription_crypto(
            url=bill.pay_url, bill=bill_id
        ),
    )


@dp.callback_query_handler(text_contains="sccheck_", state=FSM.subscription_choise_pay)
async def check_subscription_crypto(call: types.CallbackQuery, crypto: AioCryptoPay):
    user_id = call.from_user.id
    bill_id = str(call.data[8:])
    print(call)
    info = await sqlite_db.get_check_subscription(bill_id)
    invoices = await crypto.get_invoices(invoice_ids=int(bill_id))
    print(invoices)
    print(invoices.status)
    if info:
        if str(invoices.status) == "paid":
            await sqlite_db.sql_give_subscription(user_id, bill_id)
        else:
            await call.message.answer(
                "<b>Вы пока не оплатили счет</b>",
                parse_mode="HTML",
                reply_markup=client_kb.buy_menu_balance_crypto(False, bill=bill_id),
            )
    else:
        await call.message.answer("Счет не найден")


@dp.callback_query_handler(text="exit_lk", state="*")
async def command_personal_cabinet(callback: types.CallbackQuery):
    """
    Вывод личного кабинета пользователя
    """
    await callback.message.delete()
    user_id = callback.message.from_user.id
    await sqlite_db.check_user_in_db(user_id)
    balance, middle_time = await sqlite_db.get_user_details_from_db(user_id)

    if middle_time <= 0:
        subscription_status = "Нет ❌"
    else:
        subscription_status = str(datetime.timedelta(seconds=middle_time))

    await callback.message.answer(
        f"🏠 Личный кабинет 🛠\n"
        f"Здесь ты можешь узнать свой баланс и пополнить его\n\n"
        f"Ваш 🆔: {user_id}\n"
        f"Баланс 💰: {balance} руб.\n"
        f"Подписка: {subscription_status}",
        reply_markup=client_kb.kb_top_up_balance,
    )
